/*
 * un petit programme de demonstration qui n'utilise que l'analyse lexicale.
 * Permet principalement de tester la correction de l'analyseur lexical et de
 * l'interface entre celui-ci et le programme qui l'appelle.
 */
#include "main.h"
#include "Projet.h"
#include <stdio.h>
#include <string.h>

/* yytext contient le fragment du texte d'entree qui correspond a la derniere
 * unite lexicale reconnue. Son contenu est ecrase a chaque appel a lex.
 */
extern char *yytext;
extern int yylineno;


/* Cette variable sert a interfacer lex avec le programme qui l'appelle
 * notamment pour s transmettre de l'information, en plus du type d'unite
 * reconnue.
 *
 * Le type YYSTYPE est defini dans le fichier main.h
 */
YYSTYPE yylval;

typedef struct list {
	struct list* l;
	char* id;
	int line;
} list;

void add(list* l, char* id, int line) {
	list* newl = (list*) malloc(sizeof(list));
	newl->l = NULL;
	newl->id = strdup(id);
	newl->line = line;
	l->l = newl;
}

void addToEnd(list* l, char* id, int line) {
	while(l->l != NULL) {
		l = l->l;
	}

	add(l, id, line);
}

int exists(list* l, char* id) {
	while(l != NULL) {
		if(!strcmp(id, l->id))
			return 1;
		l = l->l;
	}

	return 0;
}

void afficheL(list* l) {
	while(l != NULL) {
		printf("Ident %s: %d\n", l->id, l->line);
		l = l->l;
	}
}


/* Le type "etiquette" est defini dans main.h.
 * Il sera complete ulterieurement et servira a etiqueter les noeuds
 * des arbres de syntaxe abstraite.
*/
char * OpDecompile(etiquette op) {
  switch (op) {
  case EQ:    return "=";
  case LT:    return "<";
  case GT:    return ">";
  case LE:    return "<=";
  case GE:    return ">=";
  case NEQ:   return "<>";
  default:
    fprintf(stderr, "Op. inattendu: %c", op);
    abort();
  }
}


/* lit un "programme" sur l'entrée standard, et appelle l'analyseur lexical
 * pour en reconnaitre les differentes unites.
 * Se contente pour l'instant d'ecrire sur son entree standard ce qui a ete
 * reconnu, dans certains cas (incomplet).
 */

int main(int argc, char **argv) {
	int token; char *s;
	int sumCSTE=0, sumCOMM=0, sumSTRING=0;
	list* idList=NULL;

	while (1) {
		token = yylex();

		switch (token) {
			case 0:
				printf("Fin de l'analyse lexicale\n");
				printf("Entités reconnues, avec la ligne de leur premiere occurrence:\n");
				afficheL(idList);
				printf("Somme CSTE: %d\tNb COMM: %d\tNb STRING: %d\n", sumCSTE, sumCOMM, sumSTRING);
				return 0;
			case IF:
				printf("Test-lex.Condition IF\n");
			break;
			case THEN:
				printf("Test-lex.Condition THEN\n");
			break;
			case ELSE:
				printf("Test-lex.Condition ELSE\n");
			break;
			case ID:
				printf("Test-lex.Ident: %s\n", yylval.S);

				if(idList == NULL) {
					idList = (list*) malloc(sizeof(list));
					idList->l = NULL;
					idList->id = strdup(yylval.S);
					idList->line = yylineno;
				}
				else if(!exists(idList, yylval.S))
					addToEnd(idList, yylval.S, yylineno);

			break;
			case CSTE:
				printf("Test-lex.Constante entiere: %d\n", (int)yylval.E);
				sumCSTE += (int)yylval.E;
				printf("LOLZ: %d\n", yylineno);
			break;
			case RELOP:
				printf("Test-lex.Operateur de comparaison: '%s'\n", OpDecompile(yylval.C));
			break;
			case AFF:
				printf("Test-Lex.Symbole d'affectation\n");
			break;
			case STRING:
				printf("Test-Lex.Chaine de caracteres: %s\n", yytext);
				sumSTRING++;
			break;
			case CLASS:
				printf("Test-Lex.Def de classe\n");
			break;
			case EXTENDS:
				printf("Test-Lex.Heritage\n");
			break;
			case VAL:
				printf("Test-Lex.Def de constante\n");
			break;
			case VAR:
				printf("Test-Lex.Def de variable\n");
			break;
			case NW:
				printf("Test-Lex.Allocation NEW\n");
			break;
			case DEF:
				printf("Test-Lex.DEF de méthode\n");
			break;
			case RETURNS:
				printf("Test-Lex.Retour de valeur\n");
			break;
			case IS:
				printf("Test-Lex.Def de bloc IS\n");
			break;
			case OVERRIDE:
				printf("Test-Lex.Redefinition\n");
			break;
			case SELF:
				printf("Test-Lex.Mot clef SELF\n");
			break;
			case SUPER:
				printf("Test-Lex.Mot clef SUPER\n");
			break;
			default: printf("Test-Lex. Autre symbole: %c\n", token);
		}
	}
}

